home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Utilities / MView / gxu / edgeoutline.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-09-30  |  11.6 KB  |  368 lines

  1. /*//////////////////////////////////////////////////////////////////////////////
  2. //
  3. // File: stripoutline.cpp
  4. //
  5. // Copyright (C) 1999 Microsoft Corporation. All Rights Reserved.
  6. //
  7. //
  8. //////////////////////////////////////////////////////////////////////////////*/
  9.  
  10. #include "pchgxu.h"
  11.  
  12. #include "EdgeOutline.h"
  13.  
  14. CEdgeOutline::CEdgeOutline()
  15.   :m_pDevice(NULL),
  16.     m_pIndexBuffer(NULL),
  17.     m_rgaeAttributeTable(NULL),
  18.     m_caeAttributeTable(0),
  19.     m_pDeclObj(NULL),
  20.     m_bEmulate32BitIndex(FALSE)
  21. {
  22. }
  23.  
  24. CEdgeOutline::~CEdgeOutline()
  25. {
  26.     GXRELEASE(m_pIndexBuffer);
  27.     GXRELEASE(m_pDevice);
  28.     GXRELEASE(m_pDeclObj);
  29.  
  30.     delete []m_rgaeAttributeTable;
  31. }
  32.  
  33. static inline DWORD FindNeighbor
  34.     (
  35.     CONST DWORD *pdwAdjacency, 
  36.     DWORD iFace
  37.     )
  38. {
  39.     if (pdwAdjacency[0] == iFace)
  40.         return 0;
  41.     else if (pdwAdjacency[1] == iFace)
  42.         return 1;
  43.     else 
  44.         return 2;
  45. }
  46.  
  47. template<class UINT_IDX>
  48. BOOL BCrease(DWORD iFace, DWORD iPoint, DWORD *rgdwAdjacency, UINT_IDX *pwFaceIndices)
  49. {
  50.     DWORD iNeighbor;
  51.     DWORD iEdge;
  52.  
  53.     GXASSERT(iPoint < 3);
  54.  
  55.     iNeighbor = rgdwAdjacency[(iFace * 3) + iPoint];
  56.     if (iNeighbor == UNUSED32)
  57.         return TRUE;
  58.  
  59.     GXASSERT(rgdwAdjacency[(iFace * 3) + iPoint] != UNUSED32);
  60.  
  61.     iEdge = FindNeighbor(&rgdwAdjacency[iNeighbor * 3], iFace);
  62.  
  63.     if ((pwFaceIndices[iNeighbor * 3 + iEdge] == pwFaceIndices[iFace * 3 + ((iPoint+1)%3)])
  64.         && (pwFaceIndices[iNeighbor * 3 +((iEdge+1)%3)] == pwFaceIndices[iFace * 3 + iPoint]))
  65.     {
  66.         return FALSE;
  67.     }
  68.     else 
  69.     {
  70.         return TRUE;
  71.     }
  72. }
  73.  
  74.  
  75. HRESULT
  76. CEdgeOutline::Init(ID3DXBaseMesh *ptmMesh, DWORD *rgdwAdjacency)
  77. {
  78.     HRESULT hr = S_OK;
  79.     BOOL b16BitIndex;
  80.     DWORD cBytesPerIndex;
  81.     DWORD iPoint;
  82.     DWORD iFace;
  83.     D3DXATTRIBUTERANGE *rgaeAttributeTableMesh = NULL;
  84.     PBYTE pbFaceIndices = NULL;
  85.     PBYTE pbLineIndices = NULL;
  86.     PBYTE pbSrc;
  87.     PBYTE pbDest;
  88.     DWORD iLineOffset;
  89.     DWORD iAttr;
  90.     DWORD dwNeighbor;
  91.     DWORD iFaceEnd;
  92.     BOOL bCrease;
  93.     DWORD cFacesCur;
  94.     D3DCAPS9 Caps;
  95.  
  96.     // is the mesh 16 bit?
  97.     b16BitIndex = !(ptmMesh->GetOptions() & D3DXMESH_32BIT);
  98.     cBytesPerIndex = (b16BitIndex ? 2:4);
  99.  
  100.     hr = CreateEmptyOutline();
  101.     if (FAILED(hr))
  102.         goto e_Exit;
  103.  
  104.     ptmMesh->GetDeclaration(m_pDecl);
  105.     m_cBytesPerVertex = D3DXGetDeclVertexSize(m_pDecl, 0);
  106.  
  107.     ptmMesh->GetDevice(&m_pDevice);
  108.  
  109.     hr = m_pDevice->CreateVertexDeclaration(m_pDecl, &m_pDeclObj);
  110.     if (FAILED(hr))
  111.         goto e_Exit;
  112.  
  113.     hr = ptmMesh->GetAttributeTable(NULL, &m_caeAttributeTable);
  114.     if (FAILED(hr))
  115.         goto e_Exit;
  116.  
  117.     // check for no attribute table and/or no adjacency
  118.     if ((m_caeAttributeTable == 0) || (rgdwAdjacency == NULL))
  119.     {
  120.         // not attribute sorted!  just return for now
  121.         goto e_Exit;
  122.     }
  123.  
  124.     rgaeAttributeTableMesh = new D3DXATTRIBUTERANGE[m_caeAttributeTable];
  125.     m_rgaeAttributeTable = new D3DXATTRIBUTERANGE[m_caeAttributeTable];
  126.     if ((rgaeAttributeTableMesh == NULL) || (rgaeAttributeTableMesh == NULL))
  127.     {
  128.         hr = E_OUTOFMEMORY;
  129.         goto e_Exit;
  130.     }
  131.  
  132.     hr = ptmMesh->GetAttributeTable(rgaeAttributeTableMesh, NULL);
  133.     if (FAILED(hr))
  134.         goto e_Exit;
  135.  
  136.     // now initialize the edge attribute table
  137.     for (iAttr = 0; iAttr < m_caeAttributeTable; iAttr++)
  138.     {
  139.         m_rgaeAttributeTable[iAttr] = rgaeAttributeTableMesh[iAttr];
  140.         m_rgaeAttributeTable[iAttr].FaceStart = 0;
  141.         m_rgaeAttributeTable[iAttr].FaceCount = 0;
  142.     }
  143.  
  144.     ptmMesh->LockIndexBuffer(D3DLOCK_READONLY, (LPVOID*)&pbFaceIndices);
  145.  
  146.     for (iAttr = 0; iAttr < m_caeAttributeTable; iAttr++)
  147.     {
  148.         // first figure out the counts for the number of creases per attribute group
  149.         iFaceEnd = rgaeAttributeTableMesh[iAttr].FaceStart + rgaeAttributeTableMesh[iAttr].FaceCount;
  150.         for (iFace = rgaeAttributeTableMesh[iAttr].FaceStart; iFace < iFaceEnd; iFace++)
  151.         {
  152.             for (iPoint = 0; iPoint < 3; iPoint++)
  153.             {
  154.                 dwNeighbor = rgdwAdjacency[iFace * 3 + iPoint];
  155.  
  156.                 // if the neigbor is less than the current face, we have already looked at this edge
  157.                 //    if unused, just skip... not a crease
  158.                 if (dwNeighbor < iFace)
  159.                     continue;
  160.  
  161.                 if (b16BitIndex)
  162.                 {
  163.                     bCrease = BCrease<UINT16>(iFace, iPoint, rgdwAdjacency, (UINT16*)pbFaceIndices);
  164.                 }
  165.                 else
  166.                 {
  167.                     bCrease = BCrease<UINT32>(iFace, iPoint, rgdwAdjacency, (UINT32*)pbFaceIndices);
  168.                 }
  169.  
  170.                 if (bCrease)
  171.                 {
  172.                     // add one to the count of creases for this attribute
  173.                     m_rgaeAttributeTable[iAttr].FaceCount += 1;
  174.                 }
  175.             }
  176.         }
  177.     }
  178.  
  179.     // now setup the table to have the correct offsets into the index buffer
  180.     //   now that we have calculated the FaceCount field (calc the FaceStarts...)
  181.     cFacesCur = 0;
  182.     for (iAttr = 0; iAttr < m_caeAttributeTable; iAttr++)
  183.     {
  184.         m_rgaeAttributeTable[iAttr].FaceStart = cFacesCur;
  185.         cFacesCur += m_rgaeAttributeTable[iAttr].FaceCount;
  186.  
  187.         // reset the face count, to be used in the second pass as current position in buffer
  188.         //   will become the count by the end of the pass
  189.         m_rgaeAttributeTable[iAttr].FaceCount = 0;
  190.     }
  191.  
  192.     // just exit if there are no creases
  193.     if (cFacesCur == 0)
  194.         goto e_Exit;
  195.  
  196.     m_pDevice->GetDeviceCaps(&Caps);
  197.  
  198.     // if there are too many vertices, or the max vertex index is below 16bit (means no 32 bit support)
  199.     //    then we need to emulate
  200.     if (!b16BitIndex && ((Caps.MaxVertexIndex < ptmMesh->GetNumVertices()) || (Caps.MaxVertexIndex <= 0xffff) || (Caps.MaxPrimitiveCount < cFacesCur)))
  201.     {
  202.         m_bEmulate32BitIndex = TRUE;
  203.     }
  204.     else
  205.     {
  206.         m_bEmulate32BitIndex = FALSE;
  207.     }
  208.  
  209.     hr = m_pDevice->CreateIndexBuffer(cFacesCur * 2 * cBytesPerIndex, D3DUSAGE_SOFTWAREPROCESSING, 
  210.                                         (b16BitIndex ? D3DFMT_INDEX16:D3DFMT_INDEX32),
  211.                                         D3DPOOL_MANAGED, &m_pIndexBuffer, NULL);
  212.     if (FAILED(hr))
  213.         goto e_Exit;
  214.  
  215.     m_pIndexBuffer->Lock(0, 0, (PVOID*)&pbLineIndices, D3DLOCK_NOSYSLOCK);
  216.  
  217.  
  218.     // next go through and fill the index buffer
  219.     for (iAttr = 0; iAttr < m_caeAttributeTable; iAttr++)
  220.     {
  221.         // first figure out the counts for the number of creases per attribute group
  222.         iFaceEnd = rgaeAttributeTableMesh[iAttr].FaceStart + rgaeAttributeTableMesh[iAttr].FaceCount;
  223.         for (iFace = rgaeAttributeTableMesh[iAttr].FaceStart; iFace < iFaceEnd; iFace++)
  224.         {
  225.             for (iPoint = 0; iPoint < 3; iPoint++)
  226.             {
  227.                 dwNeighbor = rgdwAdjacency[iFace * 3 + iPoint];
  228.  
  229.                 // if the neigbor is less than the current face, we have already looked at this edge
  230.                 //    if unused, just skip... not a crease
  231.                 if (dwNeighbor < iFace)
  232.                     continue;
  233.  
  234.                 if (b16BitIndex)
  235.                 {
  236.                     bCrease = BCrease<UINT16>(iFace, iPoint, rgdwAdjacency, (UINT16*)pbFaceIndices);
  237.                 }
  238.                 else
  239.                 {
  240.                     bCrease = BCrease<UINT32>(iFace, iPoint, rgdwAdjacency, (UINT32*)pbFaceIndices);
  241.                 }
  242.  
  243.                 if (bCrease)
  244.                 {
  245.                     iLineOffset = m_rgaeAttributeTable[iAttr].FaceStart + m_rgaeAttributeTable[iAttr].FaceCount;
  246.                     m_rgaeAttributeTable[iAttr].FaceCount += 1;
  247.  
  248.                     pbSrc  = pbFaceIndices + ((iFace * 3 + iPoint) * cBytesPerIndex);
  249.                     pbDest = pbLineIndices + iLineOffset * 2 * cBytesPerIndex;
  250.                     memcpy(pbDest, pbSrc, cBytesPerIndex);
  251.                 
  252.                     pbSrc  = pbFaceIndices + ((iFace * 3 + ((iPoint+1)%3)) * cBytesPerIndex);
  253.                     pbDest += cBytesPerIndex;
  254.                     memcpy(pbDest, pbSrc, cBytesPerIndex);                
  255.                 }
  256.             }
  257.         }
  258.     }
  259.  
  260. e_Exit:
  261.     delete []rgaeAttributeTableMesh;
  262.  
  263.     if (pbFaceIndices != NULL)
  264.         ptmMesh->UnlockIndexBuffer();
  265.  
  266.     if (pbLineIndices != NULL)
  267.         m_pIndexBuffer->Unlock();
  268.  
  269.     return hr;
  270. }
  271.  
  272. HRESULT
  273. CEdgeOutline::Draw(LPD3DXBASEMESH ptmDrawMesh, DWORD iAttrib)
  274. {
  275.     HRESULT hr;
  276.     LPDIRECT3DVERTEXBUFFER9 pVertexBuffer;
  277.     DWORD iSubset;
  278.  
  279.     DWORD *pdwLineIndices;
  280.     PBYTE pbLine;
  281.     PBYTE pbPoints;
  282.     DWORD iLine;
  283.     DWORD iLineStart;
  284.     DWORD iLineEnd;
  285.  
  286.     if ((iAttrib < m_caeAttributeTable) && (m_rgaeAttributeTable[iAttrib].AttribId == iAttrib))
  287.     {
  288.         iSubset = iAttrib;
  289.     }
  290.     else
  291.     {
  292.         // look for the correct attribute table entry to draw
  293.         for (iSubset = 0; iSubset < m_caeAttributeTable; iSubset++)
  294.         {
  295.             if (m_rgaeAttributeTable[iSubset].AttribId == iAttrib)
  296.             {
  297.                 break;
  298.             }
  299.         }
  300.     }
  301.  
  302.     if (iSubset < m_caeAttributeTable)
  303.     {
  304.         if (m_rgaeAttributeTable[iSubset].FaceCount > 0)
  305.         {
  306.             if (!m_bEmulate32BitIndex)
  307.             {
  308.                 ptmDrawMesh->GetVertexBuffer(&pVertexBuffer);
  309.                 m_pDevice->SetVertexDeclaration(m_pDeclObj);
  310.                 m_pDevice->SetStreamSource(0, pVertexBuffer, 0, m_cBytesPerVertex);
  311.                 m_pDevice->SetIndices(m_pIndexBuffer);
  312.  
  313.                 hr = m_pDevice->DrawIndexedPrimitive(D3DPT_LINELIST, 
  314.                                              0, 0, m_rgaeAttributeTable[iSubset].VertexStart + m_rgaeAttributeTable[iSubset].VertexCount,
  315.                                              m_rgaeAttributeTable[iSubset].FaceStart * 2, 
  316.                                              m_rgaeAttributeTable[iSubset].FaceCount);
  317.                 if (FAILED(hr))
  318.                     return hr;
  319.  
  320.                 GXRELEASE(pVertexBuffer);
  321.             }
  322.             else
  323.             {
  324.                 GXASSERT(ptmDrawMesh->GetOptions() & D3DXMESH_32BIT);
  325.  
  326.                 hr = ptmDrawMesh->LockVertexBuffer(D3DLOCK_READONLY, (PVOID*)&pbPoints);
  327.                 if (FAILED(hr))
  328.                     return hr;
  329.  
  330.                 hr = m_pIndexBuffer->Lock(0, 0, (PVOID*)&pdwLineIndices, D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY);
  331.                 if (FAILED(hr))
  332.                     return hr;
  333.  
  334.                 pbLine = (PBYTE)_alloca(m_cBytesPerVertex * 2);
  335.  
  336.                 iLineStart = m_rgaeAttributeTable[iSubset].FaceStart * 2;
  337.                 iLineEnd = iLineStart + m_rgaeAttributeTable[iSubset].FaceCount * 2;
  338.                 for (iLine = iLineStart; iLine < iLineEnd; iLine+=2)
  339.                 {
  340.                     memcpy(pbLine, pbPoints + pdwLineIndices[iLine]*m_cBytesPerVertex, m_cBytesPerVertex);
  341.                     memcpy(pbLine + m_cBytesPerVertex, pbPoints + pdwLineIndices[iLine+1]*m_cBytesPerVertex, m_cBytesPerVertex);
  342.  
  343.                     hr = m_pDevice->DrawPrimitiveUP(D3DPT_LINELIST, 1, pbLine, m_cBytesPerVertex);
  344.                     if (FAILED(hr))
  345.                         return hr;
  346.                 }
  347.  
  348.                 ptmDrawMesh->UnlockVertexBuffer();
  349.                 m_pIndexBuffer->Unlock();
  350.             }
  351.         }
  352.     }
  353.     return S_OK;
  354. }
  355.  
  356. HRESULT
  357. CEdgeOutline::CreateEmptyOutline()
  358. {
  359.     delete []m_rgaeAttributeTable;
  360.     m_rgaeAttributeTable = NULL;
  361.     m_caeAttributeTable = 0;
  362.     GXRELEASE(m_pIndexBuffer);
  363.     GXRELEASE(m_pDevice);
  364.     GXRELEASE(m_pDeclObj);
  365.  
  366.     return S_OK;
  367. }
  368.